//
// Created by sgyt on 2020/4/30.
// 字节锁
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "byte_lock.h"

static int	pfd1[2], pfd2[2];

void
TELL_WAIT(void)
{
    if (pipe(pfd1) < 0 || pipe(pfd2) < 0)
    {
        perror("pipe error");
    }
}

void
TELL_PARENT(pid_t pid)
{
    if (write(pfd2[1], "c", 1) != 1)
    {
        perror("write error");
    }
}

void
WAIT_PARENT(void)
{
    char	c;

    if (read(pfd1[0], &c, 1) != 1)
        perror("read error");

    if (c != 'p')
        perror("WAIT_PARENT: incorrect data");
}


void
TELL_CHILD(pid_t pid)
{
    if (write(pfd1[1], "p", 1) != 1)
        perror("write error");
}

void
WAIT_CHILD(void)
{
    char	c;

    if (read(pfd2[0], &c, 1) != 1)
        perror("read error");

    if (c != 'c')
        perror("WAIT_CHILD: incorrect data");
}

/**
 * 判断是否能上锁
 * @param fd
 * @param type
 * @param offset
 * @param where
 * @param len
 * @return
 */
pid_t lock_test(int fd,int type,off_t offset,int where,off_t len)
{
    struct flock lock;

    lock.l_type = type;
    lock.l_len = len;
    lock.l_whence = where;
    lock.l_start = offset;

    //申请锁
    if(fcntl(fd,F_GETLK,&lock) < 0)
    {
        perror("fcntl is error\n");
        exit(EXIT_FAILURE);
    }

    if(lock.l_type == F_UNLCK)
    {
        printf("can not get lock\n");
        exit(EXIT_FAILURE);
    }

    return lock.l_pid;

}

/**
 * 简化函数
 * @param fd
 * @param cmd
 * @param type
 * @param offset
 * @param where
 * @param len
 * @return
 */
int lock_reg(int fd,int cmd,int type,off_t offset,int where,off_t len)
{
    struct flock lock;

    lock.l_type = type;
    lock.l_len = len;
    lock.l_whence = where;
    lock.l_start = offset;

    //申请锁
    return (fcntl(fd,cmd,&lock));
}




static void lockabyte(const char *name,int fd,off_t offset)
{
    if(writew_lock(fd,offset,SEEK_SET,1) < 0)
    {
        perror("write lock is error");
    }
    printf("%s: go the lock ,byte %lld\n",name,(long long)offset);
}


int main(int argc,char *argv[])
{
    int fd;
    pid_t pid;

    fd = open("templock",O_RDWR|O_CREAT ,777);
    if(fd < 0)
    {
        perror("open is errror\n");
    }
    //输入
    if(write(fd,"ad",2) < 0)
    {
        perror("write is error\n");
    }

    TELL_WAIT();
    pid = fork();
    if(pid < 0)
    {
        perror("perror is error\n");
    }else if(pid == 0)
    {
        //子进程
        lockabyte("child",fd,0);
        TELL_PARENT(getppid());
        WAIT_PARENT();
        lockabyte("child",fd,1);
    }else{
        lockabyte("parent",fd,1);
        TELL_CHILD(pid);
        WAIT_CHILD();
        lockabyte("parent",fd,0);
    }

    return 0;
}


